from contextlib import asynccontextmanager

from fastapi import FastAPI, Request, Depends, Security
from fastapi.security import APIKeyHeader

from app.api.endpoint import demo
from app.constants import API_PREFIX, AUTHORIZATION
from app.core.config import settings
from app.core.database import disconnect_db, remove_listener
from app.core.log import print_startup_log
from app.core.nacos import register_service, deregister_service
from app.core.redis import connect_redis, disconnect_redis
from app.decorator.limit import limit
from app.event.event import register_event_handler, unregister_event_handler
from app.exception import init_exception_handler
from app.middleware import CORSMiddleware, TraceMiddleware, SameTokenMiddleware, AuthMiddleware, LoggingMiddleware
from app.utils.ip_address import close_searcher


@asynccontextmanager
async def lifespan(app: FastAPI):
    """ 应用生命周期事件 """
    # 注册Nacos服务
    await register_service()
    # 连接Redis
    await connect_redis()
    # 注册事件处理器
    register_event_handler()
    # 打印启动成功日志
    print_startup_log()

    yield

    # 断开Redis连接
    await disconnect_redis()
    # 注销事件处理器
    unregister_event_handler()
    # 关闭全局 XdbSearcher 实例，释放资源
    close_searcher()
    # 注销sqlalchemy事件监听
    remove_listener()
    # 断开数据库连接
    await disconnect_db()
    # 注销Nacos上的服务
    await deregister_service()

# swagger安全方案配置
api_key_header = APIKeyHeader(name=AUTHORIZATION, scheme_name="basic")
def security_scheme(api_key: str = Security(api_key_header)):
    return api_key

app = FastAPI(
    lifespan=lifespan,
    title=settings.swagger_title,
    description=settings.swagger_description,
    version=settings.app_version,
    contact=settings.swagger_contact,  # 联系人信息, 比较坑的是三个字段都不能为空
    docs_url=settings.swagger_docs_url,
    terms_of_service=settings.swagger_terms_of_service,
    license_info=settings.swagger_license,
    openapi_url=settings.swagger_openapi_url,
    servers=settings.swagger_servers_item,
    dependencies=[Depends(security_scheme)]
)

# 初始化全局异常处理
init_exception_handler(app)

# 注册中间件 说明；中间件越在下方越先执行
app.add_middleware(LoggingMiddleware)  # 4
app.add_middleware(AuthMiddleware)  # 3
app.add_middleware(TraceMiddleware)  # 2
app.add_middleware(SameTokenMiddleware)  # 1
CORSMiddleware.setup(app)  # 注册CORS中间件

# 包含路由
app.include_router(demo.router, prefix=API_PREFIX)


@app.get(f"{API_PREFIX}/health", summary="健康检测")
@limit(name="健康检测接口限流(同一个ip地址1分钟只能访问5次)", period=60, count=5, describe="您的操作过于频繁，请稍后再试")
async def health(request: Request):
    """ 健康监测 """
    return {"ok": True}
